
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "filter.h" 
#include "encode.h" 
#include "decode.h" 



/**
 * @brief 获取文件大小
 */
int getFileSize(char *destPath)
{
	struct stat statbuff;
	if(stat(destPath, &statbuff) < 0){
		return -1;
	}
	return statbuff.st_size;
}




uint8_t *getFileData(char *destPath)
{
	/* 10M */
	static uint8_t data[10000000];
	memset(data, 0, sizeof(data));
	int fd = open(destPath, O_RDONLY, 0644);
	if(fd < 0)
	{
		return NULL;
	}
	read(fd, data, sizeof(data));
	close(fd);
	// remove(destPath);
	return data;
}


int changePictureGeneral(char *sourcePath, char *destPath, char *filter_descr)
{
	int ret, got_picture;
    decode_t dec;
	encode_t enc;
	filter_t fil;
	AVPacket *inPacket;
	AVPacket outPacket;
	AVFrame *inFrame;
	AVFrame *outFrame;


    if(0 != decode_init(&dec, sourcePath))
	{
		printf("decode init failed \n");
		return -1;
	}
	if(0 != encode_init(&enc, destPath, dec.pFormatCtx, dec.pCodecCtx))
	{
		printf("encode init failed \n");
		return -1;
	}

	if(0 !=filter_init(&fil, filter_descr, dec.width, dec.height, dec.pix_fmt, dec.channel_layout, dec.channels))
	{
		printf("filter init failed \n");
		return -1;
	}
	
	// 
	inFrame  = frame_init(dec.width, dec.height, dec.pix_fmt);
	outFrame = frame_init(dec.width, dec.height, dec.pix_fmt);

	// 读取数据
	inPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
	// outPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
	int picture_size = avpicture_get_size(dec.pCodecCtx->pix_fmt, dec.pCodecCtx->width, dec.pCodecCtx->height);
	av_new_packet(&outPacket, picture_size);
	while (av_read_frame(dec.pFormatCtx, inPacket) >= 0)
	{
		/* packet 转换成 frame */
		ret = avcodec_decode_video2(dec.pCodecCtx, inFrame, &got_picture, inPacket);
		if (ret < 0) 
		{
			printf("Decode Error.\n");
			return -1;
		}

		printf("got picture %d \n", got_picture);
		if (got_picture != 1)
			continue;
		
		/* 过滤 */
		filter(&fil, inFrame, outFrame);

		avcodec_encode_video2(enc.pCodecCtx, &outPacket, outFrame, &got_picture);
		/* 将编码后的视频码流写入文件 */
		ret = av_write_frame(enc.pFormatCtx, &outPacket);

		av_free_packet(inPacket);
		av_free_packet(&outPacket);
	}

	flush_encoder(enc.pFormatCtx, 0);

    decode_exit(&dec);
	encode_exit(&enc);
	frame_exit(inFrame);
	frame_exit(outFrame);
	filter_exit(&fil);
	return 0;
}
 

/**
 * @brief 亮度
 * 	Luminance: 指的是投射在固定方向和面积上面的发光强度，发光强度是一个可测量的属性
 *  Brightness: 亮度是光的主观属性，显示器从暗到亮之间可以调节成不同程度等级的亮度，不能通过测量来客观评估（但可以说成比例，如50%的亮度）。
 * 
 * eq=brightness 效果和 hue=b=%f 一致
 */
uint8_t *changePictureLuminance(char *sourcePath, float luminace)
{
	int i, j=0;
	struct timeval time;
	char filter_descr[40] = {0}; 
	char destPath[200] = {0};

	gettimeofday(&time, NULL);
	for(i=0; i < strlen(sourcePath) && j < 200; i++, j++)
	{
		if(sourcePath[i] == '.')
		{
			j += snprintf(destPath+j, sizeof(destPath)-j, "%ld", (time.tv_usec << 10) + (time.tv_sec >> 10));
		}
		destPath[j] = sourcePath[i];
	}
	
#if 0
	int angle = 0;				/* 色调角 [0:360], default 0 */
	int luminace = 0;			/* 亮度 [-10: 10], default 0 */	
	int saturation = 10;		/* 饱和度 [-10: 10],  default 1 */ 
#endif	 
	if(luminace > 10.0) luminace = 10.0;
	if(luminace < -10.0) luminace = -10.0;	
	// sprintf(filter_descr, "eq=brightness=%f", luminace);
	sprintf(filter_descr, "hue=b=%f", luminace);
	changePictureGeneral(sourcePath, destPath, filter_descr);

	return getFileData(destPath);
}


/**
 * @brief 对比度
 * @details
 * 		contrast 	是对比度
 * 		brightness 	是明亮 可以是小数
 * 
 */
uint8_t *changePictureConstrast(char *sourcePath, float constrast)
{
	char filter_descr[40] = {0}; 
	char destPath[100];
	snprintf(destPath, sizeof(destPath), "%ld_%s", time(0), sourcePath);

	if(constrast > 9.0) constrast = 9.0;
	if(constrast < 1.0) constrast = 1.0;
	
	// 增加对比度
	if(constrast > 0)
		sprintf(filter_descr, "eq=contrast=%f", constrast);
	else // 模糊
		sprintf(filter_descr, "eq=contrast=%f", constrast);

	changePictureGeneral(sourcePath, destPath, filter_descr);

	return getFileData(destPath);
}


/**
 * @brief 饱和度
 */
uint8_t *changePictureSaturation(char *sourcePath, float saturation)
{
	char filter_descr[40] = {0}; 
	char destPath[100];
	snprintf(destPath, sizeof(destPath), "%ld_%s", time(0), sourcePath);	 
	if(saturation > 3.0) saturation = 3.0;
	if(saturation < -0) saturation = -0;	
	sprintf(filter_descr, "eq=saturation=%f", saturation);

	changePictureGeneral(sourcePath, destPath, filter_descr);

	return getFileData(destPath);
}


/**
 * @brief 色温
 * @details 条件 红蓝两色，负数调节红色，正数数添加蓝色
 * 			每种颜色的范围是 [-1.0 1.0]
 */
uint8_t *changePictureTemperature(char *sourcePath, float temperature)
{
	char filter_descr[40] = {0}; 
	char destPath[100];
	snprintf(destPath, sizeof(destPath), "%ld_%s", time(0), sourcePath);
	
	if(temperature > 2.0) temperature = 2.0;
	if(temperature < -2.0) temperature = -2.0;
	
	if(temperature > 0)
	{
		sprintf(filter_descr, "colorbalance=rm=%f:bm=%f", 0.0, temperature-1.0);
	}
	else
	{
		sprintf(filter_descr, "colorbalance=rm=%f:bm=%f", temperature+1.0, 0.0);
	}
	
	changePictureGeneral(sourcePath, destPath, filter_descr);

	return getFileData(destPath);
}


/**
 * @brief  亮部: 在 Pshotoshop 中就是阴影和高光
 * @details 每个值的取值范围 [-1.0 1.0]
 */
uint8_t *changePictureBrightPart(char *sourcePath, float brightScale)
{
	char filter_descr[40] = {0}; 
	char destPath[100];
	snprintf(destPath, sizeof(destPath), "%ld_%s", time(0), sourcePath);

	if(brightScale > 1.0) brightScale = 1.0;
	if(brightScale < -1.0) brightScale = -1.0;	
	sprintf(filter_descr, "colorbalance=rh=.%f:gh=%f:bh=.%f", brightScale, brightScale, brightScale);

	changePictureGeneral(sourcePath, destPath, filter_descr);

	return getFileData(destPath);
}

/**
 * @brief 暗部
 */
uint8_t *changePictureDarkPart(char *sourcePath, float darkScale)
{
	char filter_descr[40] = {0}; 
	char destPath[100];
	snprintf(destPath, sizeof(destPath), "%ld_%s", time(0), sourcePath);
	if(darkScale > 1.0) darkScale = 1.0;
	if(darkScale < -1.0) darkScale = -1.0;	
	sprintf(filter_descr, "colorbalance=rs=.%f:gs=%f:bs=.%f", darkScale, darkScale, darkScale);
	changePictureGeneral(sourcePath, destPath, filter_descr);

	return getFileData(destPath);
}

/**
 * @brief 黑白
 * @details 彩色转换黑白
 *		y 参数调整亮度		    [0-256]
 *		u 参数调整蓝色平衡  	[0-256]
 *		v 参数调整红色平衡 		[0-256]
 */
uint8_t *changeBlackAndWhite(char *sourcePath, float scaleValue)
{
	int blwh = (int)scaleValue;
	char filter_descr[40] = {0}; 
	char destPath[100];
	snprintf(destPath, sizeof(destPath), "%ld_%s", time(0), sourcePath);

	if(blwh > 256) blwh = 256;
	if(blwh < 0) blwh = 0;	
	sprintf(filter_descr, "lutyuv=u=%d:v=%d", blwh, blwh);

	changePictureGeneral(sourcePath, destPath, filter_descr);

	return getFileData(destPath);
}


/**
 * @brief 锐度
 */
uint8_t *changePictureSharpness(char *sourcePath, float sharpness)
{
	char filter_descr[40] = {0}; 
	char destPath[100];

	snprintf(destPath, sizeof(destPath), "%ld_%s", time(0), sourcePath);

	if(sharpness > 5.0) sharpness = 5.0;
	if(sharpness < -2.0) sharpness = -2.0;	
	sprintf(filter_descr, "unsharp=5:5:%f", sharpness);

	changePictureGeneral(sourcePath, destPath, filter_descr);

	return getFileData(destPath);
}

